using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Uow;
using TenantManagementService.Tenants;
using TenantManagementService.Monitoring;

namespace TenantManagementService.Tenants
{
    /// <summary>
    /// 租户自动续期后台服务
    /// </summary>
    public class TenantRenewalService : AsyncPeriodicBackgroundWorkerBase, ITransientDependency
    {
        private readonly IRepository<Tenant, Guid> _tenantRepository;
        private readonly IRepository<TenantConfiguration, Guid> _tenantConfigurationRepository;
        private readonly IDistributedEventBus _distributedEventBus;
        private readonly PrometheusMetricsService _prometheusMetricsService;
        private readonly ILogger<TenantRenewalService> _logger;

        public TenantRenewalService(
            AbpAsyncTimer timer,
            IRepository<Tenant, Guid> tenantRepository,
            IRepository<TenantConfiguration, Guid> tenantConfigurationRepository,
            IDistributedEventBus distributedEventBus,
            PrometheusMetricsService prometheusMetricsService,
            ILogger<TenantRenewalService> logger) : base(timer)
        {
            _tenantRepository = tenantRepository;
            _tenantConfigurationRepository = tenantConfigurationRepository;
            _distributedEventBus = distributedEventBus;
            _prometheusMetricsService = prometheusMetricsService;
            _logger = logger;

            // 每小时检查一次续期
            Timer.Period = TimeSpan.FromHours(1);
        }

        protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
        {
            _logger.LogInformation("开始执行租户自动续期检查");

            try
            {
                using var uow = UnitOfWorkManager.Begin();

                var renewalResult = await ProcessTenantRenewalsAsync();

                await uow.CompleteAsync();

                // 记录指标
                _prometheusMetricsService.Increment("tenant_renewal_checks_total");
                _prometheusMetricsService.RecordGauge("tenant_renewals_processed", renewalResult.TotalProcessed);
                _prometheusMetricsService.RecordGauge("tenant_renewals_successful", renewalResult.SuccessfulRenewals);
                _prometheusMetricsService.RecordGauge("tenant_renewals_failed", renewalResult.FailedRenewals);
                _prometheusMetricsService.RecordGauge("tenant_renewals_expired", renewalResult.ExpiredTenants);

                _logger.LogInformation(
                    "租户自动续期检查完成 - 处理: {Processed}, 成功: {Successful}, 失败: {Failed}, 过期: {Expired}",
                    renewalResult.TotalProcessed, renewalResult.SuccessfulRenewals,
                    renewalResult.FailedRenewals, renewalResult.ExpiredTenants);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "租户自动续期检查失败");
                _prometheusMetricsService.Increment("tenant_renewal_errors_total");
            }
        }

        /// <summary>
        /// 处理租户续期
        /// </summary>
        private async Task<TenantRenewalResult> ProcessTenantRenewalsAsync()
        {
            var result = new TenantRenewalResult();

            // 获取需要检查续期的租户
            var tenantsNeedingRenewal = await GetTenantsNeedingRenewalAsync();

            foreach (var tenant in tenantsNeedingRenewal)
            {
                try
                {
                    var renewalResult = await ProcessTenantRenewalAsync(tenant);
                    result.TotalProcessed++;

                    if (renewalResult.IsSuccess)
                    {
                        result.SuccessfulRenewals++;
                        _logger.LogInformation("租户 {TenantName} 续期成功", tenant.Name);
                    }
                    else
                    {
                        result.FailedRenewals++;
                        _logger.LogWarning("租户 {TenantName} 续期失败: {Reason}", tenant.Name, renewalResult.Message);
                    }
                }
                catch (Exception ex)
                {
                    result.FailedRenewals++;
                    _logger.LogError(ex, "处理租户 {TenantName} 续期时发生异常", tenant.Name);
                }
            }

            // 处理过期租户
            var expiredCount = await ProcessExpiredTenantsAsync();
            result.ExpiredTenants = expiredCount;

            return result;
        }

        /// <summary>
        /// 获取需要检查续期的租户
        /// </summary>
        private async Task<List<Tenant>> GetTenantsNeedingRenewalAsync()
        {
            var now = DateTime.UtcNow;
            var warningThreshold = now.AddDays(7); // 7天内过期开始提醒
            var autoRenewalThreshold = now.AddDays(1); // 1天内过期开始自动续期

            var queryable = await _tenantRepository.GetQueryableAsync();

            var tenants = await AsyncExecuter.ToListAsync(
                queryable.Where(t => t.IsEnabled &&
                    t.Status == TenantStatus.Active &&
                    t.SubscriptionEndTime.HasValue &&
                    t.SubscriptionEndTime.Value <= autoRenewalThreshold)
                    .OrderBy(t => t.SubscriptionEndTime)
            );

            _logger.LogDebug("找到 {Count} 个需要检查续期的租户", tenants.Count);
            return tenants;
        }

        /// <summary>
        /// 处理单个租户的续期
        /// </summary>
        private async Task<RenewalResult> ProcessTenantRenewalAsync(Tenant tenant)
        {
            if (!tenant.SubscriptionEndTime.HasValue)
            {
                return RenewalResult.Failure("租户没有订阅结束时间");
            }

            var now = DateTime.UtcNow;
            var daysUntilExpiration = (tenant.SubscriptionEndTime.Value - now).Days;

            // 获取租户的自动续期配置
            var autoRenewalConfig = await GetAutoRenewalConfigurationAsync(tenant.Id);
            var shouldAutoRenew = autoRenewalConfig?.Enabled ?? false;
            var renewalPeriod = autoRenewalConfig?.RenewalPeriod ?? TimeSpan.FromDays(30);

            // 检查是否需要续期
            if (daysUntilExpiration > 0)
            {
                // 还没有过期，检查是否需要自动续期
                if (shouldAutoRenew && daysUntilExpiration <= 1)
                {
                    return await PerformAutoRenewalAsync(tenant, renewalPeriod, autoRenewalConfig);
                }

                return RenewalResult.Success($"租户将在 {daysUntilExpiration} 天后过期");
            }

            // 已经过期了
            if (shouldAutoRenew)
            {
                return await PerformAutoRenewalAsync(tenant, renewalPeriod, autoRenewalConfig);
            }
            else
            {
                // 没有启用自动续期，需要手动处理
                await HandleExpiredTenantAsync(tenant, "自动续期未启用");
                return RenewalResult.Success("租户已过期，等待手动续期");
            }
        }

        /// <summary>
        /// 执行自动续期
        /// </summary>
        private async Task<RenewalResult> PerformAutoRenewalAsync(Tenant tenant, TimeSpan renewalPeriod, AutoRenewalConfiguration? config)
        {
            try
            {
                var oldEndTime = tenant.SubscriptionEndTime;
                var newEndTime = oldEndTime?.Add(renewalPeriod) ?? DateTime.UtcNow.Add(renewalPeriod);

                // 更新租户订阅时间
                tenant.SetSubscriptionInfo(
                    tenant.SubscriptionStartTime,
                    newEndTime,
                    tenant.MaxUserCount,
                    tenant.MaxStorageSize
                );

                tenant.ExtensionCount++;

                // 如果之前已过期，重新激活租户
                if (tenant.IsExpired())
                {
                    tenant.Activate();
                }

                await _tenantRepository.UpdateAsync(tenant, autoSave: true);

                // 发布续期事件
                await _distributedEventBus.PublishAsync(new TenantRenewedEto
                {
                    TenantId = tenant.Id,
                    TenantName = tenant.Name,
                    OldSubscriptionEndTime = oldEndTime,
                    NewSubscriptionEndTime = newEndTime,
                    ExtensionCount = tenant.ExtensionCount,
                    RenewalPeriod = renewalPeriod,
                    RenewedAt = DateTime.UtcNow,
                    AutoRenewalEnabled = true
                });

                _logger.LogInformation("租户 {TenantName} 自动续期成功 - 从 {OldEndTime} 到 {NewEndTime}",
                    tenant.Name, oldEndTime, newEndTime);

                return RenewalResult.Success($"自动续期成功，新到期时间: {newEndTime:yyyy-MM-dd HH:mm:ss}");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "租户 {TenantName} 自动续期失败", tenant.Name);
                return RenewalResult.Failure($"自动续期失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 处理过期租户
        /// </summary>
        private async Task<int> ProcessExpiredTenantsAsync()
        {
            var now = DateTime.UtcNow;
            var queryable = await _tenantRepository.GetQueryableAsync();

            var expiredTenants = await AsyncExecuter.ToListAsync(
                queryable.Where(t => t.IsEnabled &&
                    t.Status == TenantStatus.Active &&
                    t.SubscriptionEndTime.HasValue &&
                    t.SubscriptionEndTime.Value < now)
            );

            var processedCount = 0;

            foreach (var tenant in expiredTenants)
            {
                try
                {
                    await HandleExpiredTenantAsync(tenant, "订阅已过期");
                    processedCount++;

                    _logger.LogInformation("租户 {TenantName} 已过期，状态已更新", tenant.Name);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "处理过期租户 {TenantName} 失败", tenant.Name);
                }
            }

            return processedCount;
        }

        /// <summary>
        /// 处理过期租户
        /// </summary>
        private async Task HandleExpiredTenantAsync(Tenant tenant, string reason)
        {
            // 将租户状态设置为过期
            tenant.UpdateStatus(TenantStatus.Expired);
            await _tenantRepository.UpdateAsync(tenant, autoSave: true);

            // 发布过期事件
            await _distributedEventBus.PublishAsync(new TenantExpiredEto
            {
                TenantId = tenant.Id,
                TenantName = tenant.Name,
                SubscriptionEndTime = tenant.SubscriptionEndTime,
                ExpiredAt = DateTime.UtcNow,
                Reason = reason
            });
        }

        /// <summary>
        /// 获取租户的自动续期配置
        /// </summary>
        private async Task<AutoRenewalConfiguration?> GetAutoRenewalConfigurationAsync(Guid tenantId)
        {
            try
            {
                var queryable = await _tenantConfigurationRepository.GetQueryableAsync();
                var config = await AsyncExecuter.FirstOrDefaultAsync(
                    queryable.Where(c => c.TenantId == tenantId && c.Key == "auto_renewal"));

                if (config?.Value == null)
                {
                    return null;
                }

                // 解析 JSON 配置
                return System.Text.Json.JsonSerializer.Deserialize<AutoRenewalConfiguration>(config.Value);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取租户 {TenantId} 的自动续期配置失败", tenantId);
                return null;
            }
        }

        /// <summary>
        /// 手动触发续期检查
        /// </summary>
        public async Task<TenantRenewalResult> TriggerRenewalCheckAsync()
        {
            _logger.LogInformation("手动触发租户续期检查");
            return await ProcessTenantRenewalsAsync();
        }

        /// <summary>
        /// 续期指定租户
        /// </summary>
        public async Task<RenewalResult> RenewTenantAsync(Guid tenantId, TimeSpan renewalPeriod)
        {
            var tenant = await _tenantRepository.GetAsync(tenantId);
            return await ProcessTenantRenewalAsync(tenant);
        }
    }

    /// <summary>
    /// 租户续期结果
    /// </summary>
    public class TenantRenewalResult
    {
        public int TotalProcessed { get; set; }
        public int SuccessfulRenewals { get; set; }
        public int FailedRenewals { get; set; }
        public int ExpiredTenants { get; set; }
        public DateTime ProcessedAt { get; set; } = DateTime.UtcNow;
    }

    /// <summary>
    /// 续期结果
    /// </summary>
    public class RenewalResult
    {
        public bool IsSuccess { get; set; }
        public string Message { get; set; } = string.Empty;

        public static RenewalResult Success(string message)
        {
            return new RenewalResult { IsSuccess = true, Message = message };
        }

        public static RenewalResult Failure(string message)
        {
            return new RenewalResult { IsSuccess = false, Message = message };
        }
    }

    /// <summary>
    /// 自动续期配置
    /// </summary>
    public class AutoRenewalConfiguration
    {
        public bool Enabled { get; set; }
        public TimeSpan RenewalPeriod { get; set; }
        public int MaxAutoRenewalCount { get; set; } = 12; // 最多自动续期12次
        public int RenewalWarningDays { get; set; } = 7; // 提前7天警告
        public bool NotifyOnRenewal { get; set; } = true;
        public bool NotifyOnExpiration { get; set; } = true;
    }

    /// <summary>
    /// 租户续期事件
    /// </summary>
    public class TenantRenewedEto : DistributedEto
    {
        public Guid TenantId { get; set; }
        public string TenantName { get; set; } = string.Empty;
        public DateTime? OldSubscriptionEndTime { get; set; }
        public DateTime NewSubscriptionEndTime { get; set; }
        public int ExtensionCount { get; set; }
        public TimeSpan RenewalPeriod { get; set; }
        public DateTime RenewedAt { get; set; }
        public bool AutoRenewalEnabled { get; set; }
    }

    /// <summary>
    /// 租户过期事件
    /// </summary>
    public class TenantExpiredEto : DistributedEto
    {
        public Guid TenantId { get; set; }
        public string TenantName { get; set; } = string.Empty;
        public DateTime? SubscriptionEndTime { get; set; }
        public DateTime ExpiredAt { get; set; }
        public string Reason { get; set; } = string.Empty;
    }
}